/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lansupportserver;

import ObjectHandler.LanSupportMessage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Quan
 */
public class Only1ClientListener implements Runnable {

    private lansupportserver.LanSupportServer lanSupportServer;
    private lansupportserver.FrameChat frameChat;
    private lansupportserver.ExecuteCommand executeCommand;
    private lansupportserver.ViewScreen viewScreen;
    private lansupportserver.RemoteDesktop remoteDesktop;
    private int randomPort;
    private InetAddress remoteInetAddress;
    private Support.WriteString writer;
    private boolean debug = true;
    Socket listenSocket;
    Socket sendSocket;

    public Socket getSendSocket() {
        return sendSocket;
    }

    public Only1ClientListener(lansupportserver.LanSupportServer lanSupportServer, int randomPort, InetAddress remoteInetAddress) {
        this.lanSupportServer = lanSupportServer;
        this.randomPort = randomPort;
        this.remoteInetAddress = remoteInetAddress;
        writer = new Support.WriteString(debug);
    }

    private void AddMessage(String massage) {
        ShowFrameChat();
        frameChat.AddMessage(massage);
    }

    public void ShowFrameChat() {
        if (frameChat == null) {
            frameChat = new FrameChat(sendSocket);
        }
        frameChat.setVisible(true);
    }

    public void SendMessageToClient(String message) {
        LanSupportMessage lanSupportMessage = new LanSupportMessage(LanSupportMessage.ServerToClientMessageType);
        try {
            lanSupportMessage.setData(message.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(Only1ClientListener.class.getName()).log(Level.SEVERE, null, ex);
        }
        lanSupportMessage.Send(sendSocket);
    }

    public void SendGetCaptureScreenRequest() {
        LanSupportMessage lanSupportMessage = new LanSupportMessage(LanSupportMessage.ClientScreenshotType);
        lanSupportMessage.Send(sendSocket);
    }

    public void SendFile(File myFile) {
        try {
            LanSupportMessage lanSupportMessage = new LanSupportMessage(LanSupportMessage.FileType);
            byte[] data = new byte[(int) myFile.length()];
            FileInputStream fis = new FileInputStream(myFile);
            BufferedInputStream bis = new BufferedInputStream(fis);
            bis.read(data, 0, data.length);
            lanSupportMessage.setData(data);
            lanSupportMessage.Send(sendSocket);
        } catch (Exception ex) {
            Logger.getLogger(Only1ClientListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void ShowFrameExecuteCommand() {
        if (executeCommand == null) {
            executeCommand = new ExecuteCommand(sendSocket);
            executeCommand.setLocationRelativeTo(null);
        }
        executeCommand.setVisible(true);
    }

    public void StartViewScreen() {
        if (viewScreen == null) {
            this.viewScreen = new ViewScreen(sendSocket);
        }
        viewScreen.setVisible(true);
        viewScreen.SendRequest();
    }

    @Override
    public void run() {

        try {
            //listen at random port
            writer.WriteLine("Listen at port " + randomPort);
            try (ServerSocket serverSocket = new ServerSocket(randomPort)) {
                listenSocket = serverSocket.accept();
                writer.WriteLine("Received request!");

                int clientRandomPort = Integer.valueOf(ReceiveString(listenSocket));
                writer.WriteLine("Received random client port is " + clientRandomPort + " then send request to it.");
                sendSocket = new Socket(remoteInetAddress, clientRandomPort);
                writer.WriteLine("Connected!");
                this.lanSupportServer.AddConnection(remoteInetAddress, randomPort, sendSocket, frameChat, this);

                LanSupportMessage lanSupportMessage = new LanSupportMessage();

                boolean _continue = true;

                while (_continue) {
                    int error = lanSupportMessage.Receive(listenSocket);
                    if (error != 0) {
                        writer.WriteLine("Close connect with client at " + remoteInetAddress.getHostName());
                        _continue = false;
                    }
                    String type = lanSupportMessage.getType();
                    System.out.println(type);
                    byte[] data = lanSupportMessage.getData();
                    switch (type) {

                        case LanSupportMessage.CheckConnection:
                            break;

                        case LanSupportMessage.ChatMessageType:
                            String string = new String(data);
                            AddMessage(string);
                            break;

                        case LanSupportMessage.FileType:
                            lanSupportServer.SaveFile(data, remoteInetAddress.getHostAddress());
                            break;

                        case LanSupportMessage.ClientScreenshotType:
                            lanSupportServer.SaveFile(data, this.listenSocket.getInetAddress().getHostAddress());
                            break;
                        case LanSupportMessage.ViewScreenImage:
                            viewScreen.changeImage(data);
                            break;
                        case LanSupportMessage.StopViewScreen:
                            //viewScreen
                            break;

                        case LanSupportMessage.ViewRemoteDesktop:
                            remoteDesktop.changeImage(data);
                            break;
                        case LanSupportMessage.ClientScreenSize:
                            remoteDesktop.setWindowSize(data);
                            break;
                        case LanSupportMessage.ShellMessage:
                            executeCommand.showCMDResult(data);
                            break;
                        case LanSupportMessage.CloseConnection:
                            _continue = false;
                            break;
                    }
                    lanSupportMessage._clearData();
                }
                listenSocket.close();
                sendSocket.close();
                System.out.printf("Connect with client at %s is closed.\n", remoteInetAddress.getHostName());
            }
        } catch (IOException ex) {
        }
    }

    private String ReceiveString(Socket socket) throws IOException {
        InputStreamReader receiver = new InputStreamReader(socket.getInputStream());
        StringBuilder stringBuilder = new StringBuilder();
        int c;
        while ((c = receiver.read()) != LanSupportServer.CloseNumber) {
            stringBuilder.append((char) c);
        }
        return stringBuilder.toString();
    }

    @Override
    public String toString() {
        String status = null;
        if (this.listenSocket == null) {
            status = "Connecting";
        } else if (this.listenSocket.isConnected()) {
            status = "Connected";
        } else {
            status = "Closed";
        }
        return status;
    }

    public void StartRemote() {
        if (remoteDesktop == null) {
            remoteDesktop = new RemoteDesktop(sendSocket);
        }
        remoteDesktop.setVisible(true);
        remoteDesktop.SendRequest();
    }
}
